package main

import (
	"context"
	"errors"
	"github.com/gorilla/websocket"
	"time"
)

// Hub is a ws manager
type WebsocketHub struct {
	Register   chan Client
	Unregister chan Client
	Clients    map[string]Client
}

type WebsocketClient struct {
	ID    string
	Brand string
	Sdt   chan []byte
	Rdt   chan []byte
	Err   chan error
	Conn  *websocket.Conn
	Client
}

type WebsocketManager struct {
	WebsocketMap map[string]WebsocketHub
}

var WebsocketMap WebsocketManager

func init() {
	WebsocketMap = WebsocketManager{
		make(map[string]WebsocketHub),
	}
}

func (m *WebsocketManager) Add(brand string) {
	newClient := *NewWebsocketHub()
	m.WebsocketMap[brand] = newClient
	go newClient.Start()
}

func (m *WebsocketManager) Del(brand string) {
	delete(m.WebsocketMap, brand)
}

func NewWebsocketHub() *WebsocketHub {
	return &WebsocketHub{
		Register:   make(chan Client),
		Unregister: make(chan Client),
		Clients:    make(map[string]Client),
	}
}

//// Send 向连接websocket的管道chan写入数据.
//func (h *WebsocketHub) Send(message []byte, ignore client) error{
//	for id, conn := range h.Clients {
//		if id != ignore.ID {
//			conn.Sdt <- message
//		}
//	}
//	return nil
//}

// Start 启动websocket服务.
func (h *WebsocketHub) Start() {
	for {
		select {
		case conn := <-h.Register:
			h.Clients[conn.GetID()] = conn
		case conn := <-h.Unregister:
			if _, ok := h.Clients[conn.GetID()]; ok {
				close(conn.GetSdt())
				delete(h.Clients, conn.GetID())
			}
		}
	}
}

func (c *WebsocketClient) Send(message []byte) error {
	if c.Conn != nil {
		err := c.Conn.WriteMessage(1, message)
		if err != nil {
			return err
		} else {
			return nil
		}
	} else {
		return errors.New("conn is disconnect")
	}
}

// Read 读取在websocket管道中的数据.
func (c *WebsocketClient) Read() ([]byte, error) {
	ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second)
	defer func() {
		cancle()
	}()
	isdone := make(chan bool)
	message := new([]byte)
	err := new(error)
	go func() {
		select {
		case *message = <-c.Rdt:
		case *err = <-c.Err:
		}
		isdone <- true
	}()
	select {
	case <-ctx.Done(): //超时
		return nil, errors.New("read timeout")
	case <-isdone:
		if *err != nil {
			return nil, *err
		} else {
			return *message, nil
		}
	}
}

func (c *WebsocketClient) Start() {
	defer func() {
		WebsocketMap.WebsocketMap[c.Brand].Unregister <- c
		c.Conn.Close()
	}()
	for {
		n, message, err := c.Conn.ReadMessage()
		if err != nil {
			WebsocketMap.WebsocketMap[c.Brand].Unregister <- c
			c.Conn.Close()
		}
		if n == 1 {
			c.Rdt <- message
		}
	}
}

func (c *WebsocketClient) GetRdt() chan []byte {
	return c.Rdt
}

func (c *WebsocketClient) GetSdt() chan []byte {
	return c.Sdt
}

func (c *WebsocketClient) GetID() string {
	return c.ID
}
